package me.youline.dataServer.service.account;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;

import me.youline.dataServer.dao.UserBaseInfoDAO;
import me.youline.dataServer.entity.UserBaseInfo;
import me.youline.dataServer.exception.ImageScaleException;
import me.youline.dataServer.exception.UnExistDataException;
import me.youline.dataServer.service.account.UserProfileOperationInfo.UserProfileUpdateInfo;
import me.youline.dataServer.service.image.ImageScaleService;
import me.youline.dataServer.service.image.RatioImageScaleContext;
import me.youline.dataServer.service.support.file.AvatarFileLocator.AvatarFileLocationConfig;
import me.youline.dataServer.service.support.file.FileBuilder.FileEntity;
import me.youline.dataServer.service.support.file.FileLocatorManager;

import org.perf4j.aop.Profiled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 用户账户基本信息更新业务类
 * 
 * @author linhan
 *
 */
@Service
public class UserAccountUpdateService {
	private static Logger logger = LoggerFactory
			.getLogger(UserAccountUpdateService.class);

	@Autowired
	private UserBaseInfoDAO userBaseInfoDAO;

	@Autowired
	private FileLocatorManager locatorManager;

	@Autowired
	private ImageScaleService imageScaleService;

	@Profiled(tag = "service-更新用户个人信息")
	@Transactional
	public UserBaseInfo updateUserBaseInfo(UserProfileUpdateInfo updateInfo)
			throws UnExistDataException {
		UserBaseInfo oldInfo = getExistUserInfo(updateInfo.getUserId());
		UserBaseInfo updatedBaseInfo = mergeForUpdatedBaseInfo(oldInfo,
				updateInfo.getBaseInfo());
		FileResourceProcessor processor = new FileResourceProcessor(updateInfo,
				oldInfo);
		processor.setUpdatedBaseInfoResourceProps(updatedBaseInfo);
		if (oldInfo.equals(updatedBaseInfo)) {// 实体若未发生变化，则不需要重新更新
			logger.debug("user:id->{} is not need update ", oldInfo.getUserId());
			return oldInfo;
		}
		userBaseInfoDAO.save(updatedBaseInfo);
		processor.processFileResource();
		return updatedBaseInfo;
	}

	/**
	 * 根据用户ID获取用户未更新的个人信息
	 * 
	 * @param userId
	 * @return
	 * @throws UnExistDataException
	 *             当用户ID无法找到信息则抛出此异常
	 */
	protected UserBaseInfo getExistUserInfo(Long userId)
			throws UnExistDataException {
		UserBaseInfo baseInfo = userBaseInfoDAO.findOne(userId);
		if (baseInfo == null) {
			throw new UnExistDataException("用户基本信息不存在");
		}
		return baseInfo;
	}

	/**
	 * 文件资源处理器，负责设置用户基本信息中的文件资源属性，及对文件进行存储和删除
	 * 
	 * @author linhan
	 *
	 */
	class FileResourceProcessor {

		private List<FileEntity> list = new ArrayList<FileEntity>();

		private UserBaseInfo oldInfo;

		/**
		 * 该构造器会从upateInfo中抽取存在的文件输入流，并抽取为FileEntity
		 * 
		 * @param updateInfo
		 * @param oldInfo
		 */
		public FileResourceProcessor(UserProfileUpdateInfo updateInfo,
				UserBaseInfo oldInfo) {
			if (updateInfo.getAvatarFile() != null) {
				list.add(locatorManager.getAvatarFileLocator()
						.getNewFileEntity(
								new AvatarFileLocationConfig(updateInfo
										.getAvatarFile(), updateInfo
										.getUserId())));

			}
			this.oldInfo = oldInfo;
		}

		/**
		 * 为更新对象设置文件资源属性信息，当前设置头像路径
		 * 
		 * @param baseInfo
		 */
		public void setUpdatedBaseInfoResourceProps(UserBaseInfo baseInfo) {
			if (!list.isEmpty()) {
				baseInfo.setAvatarUrl(list.get(0).getFilePathExcludeRoot());
			}
		}

		/**
		 * 执行文件资源处理，当前主要是对旧头像进行清除，并保存新的头像资源
		 */
		public void processFileResource() {
			if (list.isEmpty()) {
				return;
			}
			this.deleteRelatedAvatarFile();
			this.doAvatarScale();
		}

		/**
		 * 删除与用户相关的所有尺寸头像文件
		 */
		private void deleteRelatedAvatarFile() {
			for (File f : locatorManager.getAvatarFileLocator()
					.getAllRelatedSizeFiles(oldInfo.getAvatarUrl())) {
				f.delete();
			}
		}
		
		/**
		 * 执行头像略缩
		 */
		private void doAvatarScale(){
			try {
				list.get(0).save();
				imageScaleService.scaleImage(new RatioImageScaleContext(list
						.get(0).getFile()));
			} catch (ImageScaleException | IOException e) {
				logger.error("图片文件处理失败", e);
			}
		}

	}

	/**
	 * 将提交的经过修改的用户信息与未更新的用户信息进行合并，生成进行更新的用户信息
	 * 
	 * @param old
	 * @param newObj
	 * @return
	 */
	protected UserBaseInfo mergeForUpdatedBaseInfo(UserBaseInfo old,
			UserBaseInfo newObj) {
		try {
			Long userId = old.getUserId();
			UserBaseInfo update = new UserBaseInfo();
			Field[] fields = UserBaseInfo.class.getDeclaredFields();
			for (Field f : fields) {
				if (Modifier.isFinal(f.getModifiers())) {
					continue;
				}
				f.setAccessible(true);
				if (f.get(old) != null && !f.get(old).equals(f.get(newObj))
						&& f.get(newObj) != null || f.get(old) == null) {
					f.set(update, f.get(newObj));
				} else {
					f.set(update, f.get(old));
				}
			}
			update.setUserId(userId);
			return update;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static Logger getLogger() {
		return logger;
	}

	public static void setLogger(Logger logger) {
		UserAccountUpdateService.logger = logger;
	}

	public UserBaseInfoDAO getUserBaseInfoDAO() {
		return userBaseInfoDAO;
	}

	public void setUserBaseInfoDAO(UserBaseInfoDAO userBaseInfoDAO) {
		this.userBaseInfoDAO = userBaseInfoDAO;
	}

	public FileLocatorManager getLocatorManager() {
		return locatorManager;
	}

	public void setLocatorManager(FileLocatorManager locatorManager) {
		this.locatorManager = locatorManager;
	}

	public ImageScaleService getImageScaleService() {
		return imageScaleService;
	}

	public void setImageScaleService(ImageScaleService imageScaleService) {
		this.imageScaleService = imageScaleService;
	}
	
}
